#pragma once

#include "log.hpp"
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <queue>

#define SIZE 1024

class UdpServer{
public:
    UdpServer(uint16_t port, std::string ip = "")
    :_port(port), _ip(ip), _sock(-1)
    {}

    bool initServer(){
        // 从这里开始，就是新的系统调用，来完成网络功能
        // 1. 创建 socket 通信用的 socket 
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sock < 0){
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }

        // 2. server 端需要 bind 端口的哦
        // bind: 将用户设置的IP和port在内核中和我们当前的进程强关联
        // "127.0.0.1" -> 点分十进制字符串风格的IP地址
        // 每一个区域的取值范围是[0, 255]: 1 个字节 --> 4个区域
        // 理论上一个IP地址，其实4个字节就够了
        // 分十进制风格的字符串的IP地址 <--> 4字节
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        // 服务器的IP地址和port未来也是要发送给对方主机的 --> 先要将数据发送到网络！
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        // 1. 同上，先要将点分十进制的字符串风格的IP地址 --> 4字节
        // 2. 4字节主机序列 --> 网络序列
        // 有一套接口，可以一次帮我们做完这两件事，让服务器在工作过程中，可以从容易的IP中获取数据
        if(bind(_sock, (struct sockaddr*)&local,sizeof(local)) < 0){
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }

        // 调用 log.hpp 头文件提供的函数去处理的
        logMessage(NORMAL, "init ud server done ... %s", strerror(errno));
        // done 

        return true;
    }

    void start(){
        // 作为一款网络服务器，永远不退出的！
        // 服务器启动 -> 进程 -> 常驻进程 -> 永远在内存中存在，除非服务器挂了   
        // echo server:client 给我们发送信息，我们原封不动返回
        char buffer[SIZE];
        // for(;;){   // 这样的写法也是可以的哦
        while(true){
            // 注意：peer 为纯输出型参数
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            // 输入：peer 缓冲区的大小
            // 输出：实际独到的 peer
            socklen_t len = sizeof(peer);

            char result[256];
            char key[64];
            std::string cmd_echo;
            // start 读取数据
            // ssize_t s = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, sizeof(peer));
            ssize_t s = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
            if(s > 0){
                buffer[s] = 0;  // 我们目前数据当做字符串
                // 1.输出发送的数据信息
                // 2. 是谁？
                // 你发过来的字符串指令 ls -a -l
                // if(strcasestr(buffer,"rm") != nullptr || strcasestr(buffer, "rmdir") != nullptr){
                //     std::string err_message = "坏人..." ;
                //     std::cout << err_message << buffer << std::endl;
                //     sendto(_sock, err_message.c_str(), err_message.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
                //     continue;
                // }
                // FILE* fp = popen(buffer, "r");
                // if(fp == nullptr){
                //     logMessage(ERROR, "popen:%d:%s",errno, strerror(errno));
                //     continue;
                // }
                // while(fgets(result,sizeof(result), fp)!= nullptr){
                //     cmd_echo += result;
                // }
                // fclose(fp);

                uint16_t cli_port = ntohs(peer.sin_port);
                std::string cli_ip = inet_ntoa(peer.sin_addr);

                // 调用 log.hpp 头文件提供的函数去处理的
                // printf("[%s:%d]# %s\n", cli_ip.c_str(), cli_port, buffer);
                snprintf(key, sizeof(key), "%s-%u", cli_ip.c_str(), cli_port);  // 127.0.0.1-8080
                logMessage(NORMAL, "key: %s", key);

                // std::string key_string = key;
                auto it = _users.find(key);
                if(it == _users.end()){
                    // exists
                    // 调用 log.hpp 头文件提供的函数去处理的
                    logMessage(NORMAL, "add new user : %s", key);
                    _users.insert({key, peer});
                }
            }
            // 分析和处理数据,todo
            // end. 写回数据
            // sendto(_sock, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, len);
            // sendto(_sock,cmd_echo.c_str(),cmd_echo.size(), 0,(struct sockaddr*)&peer, len);
            for(auto &iter: _users){
                std::string sendMessage = key;
                sendMessage += "# ";
                sendMessage += buffer;

                // 调用 log.hpp 头文件提供的函数去处理的
                logMessage(NORMAL, "push message to %s", iter.first.c_str());
                sendto(_sock, sendMessage.c_str(), sendMessage.size(), 0, (struct sockaddr*)&(iter.second), sizeof(iter.second));
            }
        }
    }

    ~UdpServer(){
        if(_sock >= 0) 
            close(_sock);
    }

private:
    // 一个服务器，一般必须需要IP地址和port(16位的整数)
    int _sock;
    std::string _ip;
    uint16_t _port;

    std::unordered_map<std::string, struct sockaddr_in> _users;
    std::queue<std::string> messagQueue;
};

